﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using SelfService.Helpers;
using SelfService.Model.Interface;
using SelfService.Model.Models;
using SelfService.Model.Request;
using TT;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Mvc;

namespace SelfService.Controllers.Apis;


[AuthorizeJwtWithCookie]
[ActionDescription("医保接口")]
[ApiController]
[AllRights]
[Route("api/SysSocialSecurity")]
public class SysSocialSecurityController : BaseApiController
{
    private readonly IMemoryCache _memoryCache;

    public SysSocialSecurityController(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }

    [ActionDescription("医保缴费列表")]
    [HttpGet("List")]
    public async Task<Result<SysPrescription[]>> List([FromQuery] Guid? patientId)
    {
        try
        {
            //查询患者
            var result = await this.CheckPatient(patientId, "查询医保缴费列表");
            if (result.Code != 200)
            {
                return new Result<SysPrescription[]>()
                {
                    Code = 1,
                    Message = result.Message
                };
            }
            var patient = result.Data;
            //调用HIS接口
            ISocialSecurityOrder service;
            try
            {
                var scope = Wtm.ServiceProvider.CreateScope();
                service = scope.ServiceProvider.GetRequiredService<ISocialSecurityOrder>();
            }
            catch (Exception)
            {
                return new Result<SysPrescription[]>()
                {
                    Code = 1,
                    Message = "服务端没有启用该业务"
                };
            }
            var data = await service.List(patient);
            if (data.Code == 200)
            {
                this.Logger($"查询医保缴费列表, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Debug);
                var list = new List<SysPrescription>();
                var codeList = data.Data.Select(e => e.Code).ToList();
                if (codeList.Count > 0)
                {
                    var orderList = await DC.Set<SysPrescription>()
                        .Where(e => e.PatientId == patient.ID && codeList.Contains(e.Code) && e.SocialSecurityStatus == SocialSecurityType.未结算)
                        .ToListAsync();
                    var orderIds = orderList.Select(e => (Guid?)e.ID).ToList();
                    var projectList = await DC.Set<SysPrescriptionProjects>()
                        .Where(e => orderIds.Contains(e.PrescriptionId))
                        .ToListAsync();
                    DC.Set<SysPrescriptionProjects>().RemoveRange(projectList);
                    DC.Set<SysPrescription>().RemoveRange(orderList);
                    await DC.SaveChangesAsync();
                }
                foreach (var element in data.Data)
                {
                    //保存缴费数据到数据库
                    var order = new SysPrescription();
                    order.CopyPropertyFrom(element);
                    order.ID = Guid.NewGuid();
                    order.PatientId = patient.ID;
                    order.Patient = null;
                    order.Status = SysOrderStatus.未缴费;
                    order.SocialSecurityStatus = SocialSecurityType.未结算;
                    if(order.CreateBy.IsNullOrWhiteSpace()) order.CreateBy = Wtm.LoginUserInfo.ITCode;
                    order.CreateTime ??= DateTime.Now;
                    order.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    order.UpdateTime = DateTime.Now;
                    await DC.Set<SysPrescription>().AddAsync(order);
                    await DC.SaveChangesAsync();
                    list.Add(order);
                }
                return new Result<SysPrescription[]>()
                {
                    Data = list.ToArray()
                };
            }
            else
            {
                this.Logger($"查询医保缴费列表, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Exception);
                return new Result<SysPrescription[]>
                {
                    Code = 1,
                    Message = $"查询缴费列表失败. {data.Message}"
                };
            }
        }
        catch (Exception e)
        {
            this.Logger($"查询医保缴费列表发生异常:{e.Message} | StackTrace: {e.StackTrace}", ActionLogTypesEnum.Exception);
            return new Result<SysPrescription[]>
            {
                Code = 1,
                Message = $"查询缴费列表异常. {e.Message}"
            };
        }
    }
    
    [ActionDescription("预结算(带卡信息)")]
    [HttpPost("PrePay")]
    public async Task<Result<SysPrescription>> PrePay([FromBody] PrePayRequest request)
    {
        try
        {
            var slim = await _memoryCache.GetOrCreateAsync($"{nameof(SysSocialSecurityController)}:{nameof(PrePay)}:{request.PrescriptionId}", entry =>
            {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
                return Task.FromResult(new SemaphoreSlim(1, 1));
            });
            if (!await slim.WaitAsync(TimeSpan.FromSeconds(3)))
            {
                return new Result<SysPrescription>("业务处理中, 请稍后再试");
            }
            try
            {
                var prescription = await DC.Set<SysPrescription>()
                    .Include(e => e.Patient)
                    .FirstOrDefaultAsync(e => e.ID == request.PrescriptionId);
                if (prescription == null)
                {
                    return new Result<SysPrescription>()
                    {
                        Code = 1,
                        Message = "未找到缴费记录"
                    };
                }
                if (prescription.Status != SysOrderStatus.未缴费 || prescription.SocialSecurityStatus != SocialSecurityType.未结算)
                {
                    return new Result<SysPrescription>()
                    {
                        Code = 1,
                        Message = "缴费单据状态异常, 无法预结算"
                    };
                }
                //调用HIS接口
                ISocialSecurityOrder service;
                try
                {
                    using var scope = Wtm.ServiceProvider.CreateScope();
                    service = scope.ServiceProvider.GetRequiredService<ISocialSecurityOrder>();
                }
                catch (Exception)
                {
                    return new Result<SysPrescription>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }
                prescription.CardInfo = request.CardInfo;
                var data = await service.PrePay(prescription);
                if (data.Code == 200)
                {
                    this.Logger($"医保预结算, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Debug);
                    prescription.SocialSecurityStatus = SocialSecurityType.预结算;
                    prescription.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    prescription.UpdateTime = DateTime.Now;
                    await DC.SaveChangesAsync();
                    return new Result<SysPrescription>()
                    {
                        Data = prescription
                    };
                }
                else
                {
                    this.Logger($"医保预结算失败, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Exception);
                    return new Result<SysPrescription>
                    {
                        Code = 1,
                        Message = $"医保预结算异常. {data.Message}"
                    };
                }
            }
            finally
            {
                slim.Release();
            }
        }
        catch (Exception e)
        {
            this.Logger($"医保预结算失败异常:{e.Message} | StackTrace: {e.StackTrace}", ActionLogTypesEnum.Exception);
            return new Result<SysPrescription>
            {
                Code = 1,
                Message = $"医保预结算异常. {e.Message} | {e.StackTrace}"
            };
        }
    }
        
    
    [ActionDescription("预结算")]
    [HttpGet("PrePay")]
    public async Task<Result<SysPrescription>> PrePay([FromQuery] Guid? prescriptionId)
    {
        if (prescriptionId != null)
        {
            var request = new PrePayRequest
            {
                PrescriptionId = prescriptionId.Value,
                CardInfo = ""
            };
            return await PrePay(request);
        }
        return new Result<SysPrescription>("缴费记录ID不能为空");
    }
     
    
    [ActionDescription("结算")]
    [HttpGet("Pay")]
    public async Task<Result<SysPrescription>> Pay([FromQuery] Guid? prescriptionId, [FromQuery] Guid? payId)
    {
        try
        {
            if (prescriptionId.IsNullOrEmpty())
            {
                return new Result<SysPrescription>()
                {
                    Code = 1,
                    Message = "缴费记录ID不能为空"
                };
            }
            var slim = await _memoryCache.GetOrCreateAsync($"{nameof(SysSocialSecurityController)}:{nameof(Pay)}:{prescriptionId}", entry =>
            {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
                return Task.FromResult(new SemaphoreSlim(1, 1));
            });
            
            if (!await slim.WaitAsync(TimeSpan.FromSeconds(3)))
            {
                return new Result<SysPrescription>("业务处理中, 请稍后再试");
            }
            try
            {
                var prescription = await DC.Set<SysPrescription>()
                    .Include(e => e.Pay)
                    .Include(e => e.Patient)
                    .FirstOrDefaultAsync(e => e.ID == prescriptionId);
                if (prescription == null)
                {
                    return new Result<SysPrescription>()
                    {
                        Code = 1,
                        Message = "未找到缴费记录"
                    };
                }
                
                if (prescription.Status != SysOrderStatus.未缴费 || prescription.SocialSecurityStatus != SocialSecurityType.预结算)
                {
                    return new Result<SysPrescription>
                    {
                        Code = 1,
                        Message = "缴费单据状态异常, 无法预结算"
                    };
                }

                SysPay pay;
                if (prescription.SelfAmount == 0 && prescription.Amount == prescription.ReimbursementAmount)
                {
                    pay = null;
                }
                else
                {
                    if (payId.IsNullOrEmpty())
                    {
                        return new Result<SysPrescription>()
                        {
                            Code = 1,
                            Message = "支付记录ID不能为空"
                        };
                    }
                    //查找支付记录
                    pay = DC.Set<SysPay>()
                        .Include(e => e.PayType)
                        .FirstOrDefault(e => e.ID == payId);
                    if (pay is not { PayStatus: PayStatusEnum.支付成功 })
                    {
                        return new Result<SysPrescription>
                        {
                            Code = 1,
                            Message = "支付状态异常"
                        };
                    }
                    prescription.Pay = pay;
                    prescription.PayId = pay.ID;
                }
                //调用HIS接口
                ISocialSecurityOrder service;
                try
                {
                    var scope = Wtm.ServiceProvider.CreateScope();
                    service = scope.ServiceProvider.GetRequiredService<ISocialSecurityOrder>();
                }
                catch (Exception)
                {
                    return new Result<SysPrescription>
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }
                var data = service.Pay(prescription).Result;
                if (data.Code == 200)
                {
                    this.Logger($"医保结算, 请求数据:{data.Request}, 返回数据:{data.Response}");
                    if (pay != null)
                    {
                        pay.Use = PayUseEnum.医保缴费;
                        pay.UseStatus = UseStatusEnum.成功;
                        pay.UpdateBy = Wtm.LoginUserInfo.ITCode;
                        pay.UpdateTime = DateTime.Now;
                    }
                    prescription.Status = SysOrderStatus.已缴费;
                    prescription.SocialSecurityStatus = SocialSecurityType.结算;
                    prescription.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    prescription.UpdateTime = DateTime.Now;
                    await DC.SaveChangesAsync();
                    return new Result<SysPrescription>
                    {
                        Data = prescription
                    };
                }
                else
                {
                    this.Logger($"医保结算失败, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Exception);
                    if (pay != null)
                    {
                        pay.Use = PayUseEnum.医保缴费;
                        pay.UseStatus = UseStatusEnum.失败;
                        pay.UpdateBy = Wtm.LoginUserInfo.ITCode;
                        pay.UpdateTime = DateTime.Now;
                    }
                    prescription.Status = SysOrderStatus.已缴费;
                    prescription.SocialSecurityStatus = SocialSecurityType.结算失败;
                    prescription.ErrorMessage = data.Message;
                    prescription.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    prescription.UpdateTime = DateTime.Now;
                    await DC.SaveChangesAsync();
                    return new Result<SysPrescription>
                    {
                        Code = 1,
                        Message = $"医保结算失败 {data.Message}"
                    };
                }
            }
            finally
            {
                slim.Release();
            }
        }
        catch (Exception e)
        {
            this.Logger($"医保结算异常:{e.Message} | StackTrace: {e.StackTrace}", ActionLogTypesEnum.Exception);
            return new Result<SysPrescription>
            {
                Code = 1,
                Message = $"医保结算异常. {e.Message}"
            };
        }
    }
     
    [ActionDescription("冲正")]
    [HttpGet("Reverse")]
    public async Task<Result<SysPrescription>> Reverse([FromQuery] Guid? prescriptionId)
    {
        try
        {
            if (prescriptionId.IsNullOrEmpty())
            {
                return new Result<SysPrescription>()
                {
                    Code = 1,
                    Message = "缴费记录ID不能为空"
                };
            }
            var slim = await _memoryCache.GetOrCreateAsync($"{nameof(SysSocialSecurityController)}:{nameof(Reverse)}:{prescriptionId}", entry =>
            {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);
                return Task.FromResult(new SemaphoreSlim(1, 1));
            });
            if (!await slim.WaitAsync(TimeSpan.FromSeconds(3)))
            {
                return new Result<SysPrescription>("业务处理中, 请稍后再试");
            }
            try
            {
                var prescription = await DC.Set<SysPrescription>()
                .Include(e => e.Patient)
                .FirstOrDefaultAsync(e => e.ID == prescriptionId);
                if (prescription == null)
                {
                    return new Result<SysPrescription>()
                    {
                        Code = 1,
                        Message = "未找到缴费记录"
                    };
                }
                if (prescription.Status != SysOrderStatus.未缴费 || prescription.SocialSecurityStatus != SocialSecurityType.预结算)
                {
                    return new Result<SysPrescription>()
                    {
                        Code = 1,
                        Message = "单据状态异常, 无法撤销结算"
                    };
                }
                //调用HIS接口
                ISocialSecurityOrder service;
                try
                {
                    var scope = Wtm.ServiceProvider.CreateScope();
                    service = scope.ServiceProvider.GetRequiredService<ISocialSecurityOrder>();
                }
                catch (Exception)
                {
                    return new Result<SysPrescription>()
                    {
                        Code = 1,
                        Message = "服务端没有启用该业务"
                    };
                }
                var data = service.CancelPay(prescription).Result;
                if (data.Code == 200)
                {
                    this.Logger($"医保撤销结算, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Debug);
                    prescription.SocialSecurityStatus = SocialSecurityType.冲正成功;
                    prescription.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    prescription.UpdateTime = DateTime.Now;
                    await DC.SaveChangesAsync();
                    return new Result<SysPrescription>
                    {
                        Data = prescription
                    };
                }
                else
                {
                    this.Logger($"医保撤销结算失败, 请求数据:{data.Request}, 返回数据:{data.Response}", ActionLogTypesEnum.Exception);
                    prescription.SocialSecurityStatus = SocialSecurityType.冲正失败;
                    prescription.ErrorMessage = data.Message;
                    prescription.UpdateBy = Wtm.LoginUserInfo.ITCode;
                    prescription.UpdateTime = DateTime.Now;
                    await DC.SaveChangesAsync();
                    return new Result<SysPrescription>
                    {
                        Code = 1,
                        Message = $"医保撤销结算失败. {data.Message}"
                    };
                }
            }finally
            {
                slim.Release();
            }
        }
        catch (Exception e)
        {
            this.Logger($"医保撤销结算异常:{e.Message} | StackTrace: {e.StackTrace}", ActionLogTypesEnum.Exception);
            return new Result<SysPrescription>
            {
                Code = 1,
                Message = $"医保撤销结算异常. {e.Message}"
            };
        }
    }
}